<?php
/*
 * This class serves as a tool to manage a herachhical node structure. A tree of nodes.
 */

class node {
	public $name;			//Node identificator
	//The node data object should be defined by descendents classes
	public $children=array();	//Node descendents pointer
	public $parentNode;		//Node parent pointer

	/*
	 *	It returns the node children index which name coincides with the value sent
	 */
	function has_children($name) {
		for ($i=0; $i<count($this->children); $i++) {
			if ($this->children[$i]->name==$name)  {
				return $i;
			}
		}
		return -1;
	}
	
	/*
	 * This is a essential function that should be carryed out at init to buildt the tree node from the text list of nodes
	 * This list should consist in something like this:
	array(
		"root",
		"root::site1",
		"root::site1::site2",
		"root::site3",
		"root::site3::site4",
		"root::site3::site4::site5",
		"root::site3::site4::site6"
	)
	That will result in:
	
		 - - - site1 - - - site2
	root	|				 - - - site5
		 - - - site3 - - - site4 	|
						 - - - site6
	 
	 */
	function unserialize($nodesTxt) {
		//$nodesTxt is an array of string node names splitted by the string delimiter "::"
		$stringDelimiter="::";
		foreach ($nodesTxt as $nodeTxt) {
			$nodePointer=$this;	//We point to the node. $this is a void node, acts only as a pointer to the node tree
			$nodeNamesPath=explode($stringDelimiter,$nodeTxt);
			foreach ($nodeNamesPath as $nodeName) {
				$index=$nodePointer->has_children($nodeName);
				if ($index >-1) {
					//we are navegating through a branch
					$nodePointer=$nodePointer->children[$index];
				}
				else {
					//New node because there is no such a node in the branch, we add it to the branch end
					$newNode=new node();
					$newNode->name=$nodeName;
					$newNode->parentNode=$nodePointer;
					array_push($nodePointer->children, $newNode);
					$nodePointer=$newNode;	//$nodePointer points now to the last node added. If there are more iterations more nodes will be added
				}
			}
		}
	}
	/*
	 * This functions returns a pointer to the node that coincides with the last name at the path.
	 * It is an easy task it has only to path the names at the path and points at the end one.
	 */
	function get_node_from_path($path) {
		$nodePointer=$this;	//$nodePointer points to the first node that is the pointer to the tree.
		$nodeNamesPath=explode("::",$path);
		foreach ($nodeNamesPath as $nodeName) {
			$index=$nodePointer->has_children($nodeName);	//First name at the path will go to one of the initial node branches
			if ($index >-1) {
				$nodePointer=$nodePointer->children[$index];
			}
			else {
				return null; //The searching has fail
			}
		}
		return $nodePointer; //$nodePointer points to the node children which name coincides with the last path name
	}
	/*
	 * For searching proposals we used to eliminate the candidats by deleting the last node of the tree consecutivelly.
	 * This way we can discard candidates and continue searching without getting in a loop
	 */
	function remove_children($number) {
		$result=array();
		for ($i=0; $i<count($this->children); $i++) {
			if ($i != $number) {
				array_push($result,$this->children[$i]);
			}
		}
		//we have removed the node children with the name as $name
		$this->children=$result;
	}
	/*
	 * It returns an array with the paths to every node.Llook at unserialize function for more information.
	 */
	function serialize() {
		$stringDelimiter="::";	//The delimitier glue at the text line
		$nodePointer=unserialize(serialize($this)); //we create a copy of the node tree for managing it without change the original
		$nodeStart=$nodePointer; //$nodeStart points to the first node, the index one.
		$values=array();
		while (count($nodePointer->children) > 0) {
			$value=array();
			while (count($nodePointer->children) > 0) {
				$parentPointer=$nodePointer;
				$nodePointer=$nodePointer->children[0];
				array_push($value,$nodePointer->name); //We are creating a node list from the first one to the last one from the first branch
			}
			array_push($values,implode($stringDelimiter,$value)); //We transform the array into text
			$parentPointer->remove_children(0); //we remove the last node of the branch and continue from the begining
			$nodePointer=$nodeStart; //restart to the index pointer
		}
		return $values; //the array with the paths to every node
	}
	//It returns an array with the nodes that are parent to the $nodePointer. The first node is the parent, the second will be the grandparent and so on
	function get_parents() {
		$nodePointer=$this;
		$parents=array();
		while ($nodePointer->parentNode) {
			array_push($parents, $nodePointer->parentNode);
			$nodePointer=$nodePointer->parentNode;
		}
		return $parents;
	}
}
?>